# 导入线程
from threading import Thread

# 导入需要使用的类和函数
from flask import Flask, render_template

# 导入邮件扩展包的邮件管理器和邮件类
from flask_mail import Mail, Message

# 导入URL时间序列化功能，可以实现对敏感数据的编码和解码
from itsdangerous import URLSafeTimedSerializer

app = Flask(__name__)
app.config["SECRET"] = "123456"             # 秘钥
app.config["DEBUG"] = True                  # 开启app的debug模式
app.config['MAIL_DEBUG'] = True             # 开启debug，便于调试看邮件发送信息
app.config['MAIL_SUPPRESS_SEND'] = False    # 发送邮件，为True则不发送
app.config['MAIL_SERVER'] = 'smtp.qq.com'   # 邮箱服务器
app.config['MAIL_PORT'] = 465               # 端口（根据所选的邮箱服务器来）
app.config['MAIL_USE_SSL'] = True           # 重要，qq邮箱需要使用SSL（根据所选的邮箱服务器来）
app.config['MAIL_USE_TLS'] = False          # 不需要使用TLS（根据所选的邮箱服务器来）
app.config["MAIL_USERNAME"] = "你的邮箱@qq.com"  # 你的邮箱地址
app.config["MAIL_PASSWORD"] = "你的授权码"  # 你的邮箱授权码

# 实例化邮件管理器
mail = Mail(app)


def generator_token(id_):
    """
    根据秘钥和时间戳把传入的数据进行编码
    :param id_: 要编码的数据
    :return: 编码后的字符串
    """
    # 实例化编码对象
    ser = URLSafeTimedSerializer(app.config["SECRET"])
    # 对数据进行编码
    token = ser.dumps(id_)
    return token


def send_email(msg):
    """
    开启app上下文进行发送邮件
    :param msg: 要发送的邮件
    """
    with app.app_context():
        mail.send(msg)


@app.route('/')
def hello_world():
    """
    发送邮件的功能
    :return:
    """
    # 生成编码
    token = generator_token(1)
    # 实例化邮件的对象：第一个参数：邮件标题， 第二个参数：发送发，第三个参数：接收方（是一个列表）
    message = Message("邮件验证通知", sender=app.config["MAIL_USERNAME"], recipients=["xxxxx@example.com", "xxxxx2@example.com"])
    # 显示的文本内容
    message.body = "内容"
    # 浏览器显示的页面内容，把token当成url的一部分传入模板进行发送
    message.html = render_template("email.html", token=token)
    # 开启线程异步发送邮件
    t = Thread(target=send_email, args=(message,))
    t.start()
    return '发送成功!'


@app.route('/vali_email/<token>')
def vali_email(token):
    """
    验证邮件：根据获得token进行解码，并验证是否正确
    :param token:
    :return:
    """
    # 实例化对象，使用哪个编码，就有哪个解码
    ser = URLSafeTimedSerializer(app.config["SECRET"])
    try:
        # 对token进行解码，max_age为有效时间，会根据时间戳进行比较
        id_ = ser.loads(token, max_age=300)
    except Exception as e:
        return '错误原因：%s' % e
    print(id_)
    if id_ == 1:
        return '验证通过'
    else:
        return '验证失败'

if __name__ == '__main__':
    app.run()
